#ifndef ABSTRACTMODELXMLWRITER_H
#define ABSTRACTMODELXMLWRITER_H

#include <QObject>

class QModelIndex;
class QXmlStreamWriter;
class QAbstractItemModel;
class QIODevice;
class QRect;

/** Сохраняет данные из модели в xml.
 *
 * Каждая строка интерпретируется как элемент,
 * заголовок столбца — имя отрибута.
 * Дочерние строки первой ячейки — вложенные элементы.
 * Дочерние строки других ячеек игнорируются.
 *
 *
 * |------------|------------|------------|---|
 * |Имя атрибута|Имя атрибута|Имя атрибута|...|
 * ============================================
 * |------------|------------|------------|---|
 * |  Значение  |  Значение  |  Значение  |...|
 * ||-----------|------------|------------|---|
 * || Значение  |  Значение  |  Значение  |...|
 * ||-\---------|------------|------------|---|
 * | \ \...     |    ...     |    ...     |...|
 *    | \
 *    |  |...|    ...     |    ...     |    ...     |...|
 *    |  |---|------------|------------|------------|---|
 *    |  |...|  Значение  |  Значение  |  Значение  |...|
 *    |  |---|------------|------------|------------|---|
 *    |  |...|  Значение  |  Значение  |  Значение  |...|
 *    |  |---|------------|------------|------------|---|
 *    \  |...|    ...     |    ...     |    ...     |...|
 *     \
 *      \
 *       |...|    ...     |    ...     |    ...     |...|
 *       |---|------------|------------|------------|---|
 *       |...|  Значение  |  Значение  |  Значение  |...|
 *       |---|------------|------------|------------|---|
 *       |...|  Значение  |  Значение  |  Значение  |...|
 *       |---|------------|------------|------------|---|
 *       |...|    ...     |    ...     |    ...     |...|
 *
 * У таблицы верхнего уровня есть поля(header) и имена атрибутов
 * можно брать оттуда. Для вложенных таблиц надо придумать решение.
 * Функция virtual QString getAtrName(const QModelIndex & parent, int n)
 * возвращает имя атрибута для столбца номер n для таблицы вложенной в parent.
 * Реализация по умолчанию вернёт строку с номером столбца, а
 * SimpleModelXmlReaderWriter::getAtrName() вернёт строку со значением
 * ячейки первой первой строки n-ого столбца. В своём наследнике
 * реализуйте специфичное для него поведение.
 *
 *
 * Функция virtual QRect getAreaAtr(const QModelIndex & parent) вернёт область
 * тблицы, из которой надо брать значения атрибутов.
 * AbstractModelXmlReaderWriter::getAreaAtr() всегда возвращает
 * (0, 0, m.rowCount(), columnCount()), а SimpleModelXmlReaderWriter::getAreaAtr()
 * для вложенных таблиц возвращает (1, 0, m.rowCount(), columnCount()),
 * чтобы оставить первую строку для имён атрибутов. В своём наследнике
 * реализуйте специфичное для него поведение.
 *
 * Функция virtual QString getNodeName(const QModelIndex & parent) вернёт
 * имя тега для элементов получаемых из текуей таблицы. Реализация поумолчанию
 * возвращает степень вложенности элемента.
 *
 * Если хотите разбирать на атрибуты не сплошную область, а сделать блее
 * сложныую структуру, переопределите virtual int getNodeCount(const QModelIndex & parent)
 * и virtual QString getAtrValue(const QModelIndex & parent, int nNode, int nAtr).
 * возможно в вашей реализации отпадёт нобходимость в getAreaAtr().
 *
 * @author Василий Почкаенко
 */
class AbstractModelXmlReaderWriter : public QObject{
Q_OBJECT
private:
	/** Пишет в xml.*/
	QXmlStreamWriter *writer;

	/** Модель в которую/изкоторой читаем/пишем.*/
	QAbstractItemModel *m;

	/** Записать элемент.
	 *
	 * Записывает строку, на любую ячейку которой указывает индекс.
	 * А затем вызывает себя для дочерних строк первой ячейки.
	 */
	bool writeNode(const QModelIndex & index) const;

	/** Инициализация.*/
	void init();

	/** Имя атрибута для столбца номер n для таблицы вложенной в parent.
	 *
	 * Реализация по умолчанию вернёт строку с номером столбца.
	 * @param parent индекс элемента, содержащего таблицу. parent = QModelIndex() для таблицы верхнего уровня.
	 * @param n номер столбца-атрибута.
	 */
	virtual QString getAtrName(const QModelIndex & parent, int n);

	/** Область тблицы, из которой надо брать значения атрибутов.
	 *
	 * @param parent индекс элемента, содержащего таблицу. parent = QModelIndex() для таблицы верхнего уровня.
	 * @return всегда (0, 0, m.rowCount(), columnCount()).*/
	virtual QRect getAreaAtr(const QModelIndex & parent);

	/** Имя тега для элементов получаемых из текуей таблицы.
	 *
	 * @param parent индекс элемента, содержащего таблицу. parent = QModelIndex() для таблицы верхнего уровня.
	 * @return степень вложенности элемента.*/
	virtual QString getNodeName(const QModelIndex & parent, int n);

	/** Кол-во элементов на данном уровне.*/
	virtual int getNodeCount(const QModelIndex & parent);

	/** Значение атрибута для столбца номер n для таблицы вложенной в parent.
	 *
	 * @param parent индекс элемента, содержащего таблицу. parent = QModelIndex() для таблицы верхнего уровня.
	 * @param n номер столбца-атрибута.
	 */
	virtual QString getAtrValue(const QModelIndex & parent, int nNode, int nAtr);
public:
	/** Создаёт привязку переданной модели к XML.
	 * Необходимо задать объект XML.*/
	explicit AbstractModelXmlReaderWriter(QAbstractItemModel *m = NULL, //!< Указател на модель в которую/из которой читаем/пишем.
	                                      QObject *parent = 0);
	/** Создаёт привязку переданной модели к XML.
	 * Пишет/читает XML в/из переданное устройство. Позаботтесь чтобы объект устройства существовал, пока существует привязка модели к XML.*/
	explicit AbstractModelXmlReaderWriter(QIODevice * device,           //!< Указател на устройство из/в котророго читаем/пишем.
	                                      QAbstractItemModel *m = NULL, //!< Указател на модель в которую/из которой читаем/пишем.
	                                      QObject *parent = 0);
	/** Создаёт привязку переданной модели к XML файлу с указанным именем.*/
	explicit AbstractModelXmlReaderWriter(const QString &filename,            //!< Имя файла из/в котророго читаем/пишем.
	                                      QAbstractItemModel *m = NULL, //!< Указател на модель в которую/из которой читаем/пишем.
	                                      QObject *parent = 0);
	~AbstractModelXmlReaderWriter();

	/** Возвращает текущее устройство, которое связано с AbstractModelXmlReaderWriter, или 0, если такого нет.*/
	QIODevice * device() const;


	/** Возвращает имя файла, который связан с AbstractModelXmlReaderWriter,
	 * или пустую строку, если такого нет.
	 * @see QString::isEmpty().*/
	const QString & fileName() const;

	/** Указатель на привязанную модель.*/
	QAbstractItemModel * model() const;
signals:

public slots:
	/** Записать данные в xml.*/
	void write();

	/** Установить модель.*/
	void setModel(QAbstractItemModel *m);
};

#endif // ABSTRACTMODELXMLWRITER_H
